package zdream.pmfield.test.stage.timeline;

import org.junit.Before;
import org.junit.Test;

import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;

import zdream.pmfield.data.foe.Foe;
import zdream.pmfield.data.foe.MoveTemplate;
import zdream.pmfield.stage.StageBuilderForTest;
import zdream.pmfield.stage.StageWrapper;
import zdream.pmfield.stage.message.ActionRequestMessage;
import zdream.pmfield.stage.message.TurnFinishedMessage;
import zdream.pmfield.storage.FoeTemplateStorage;
import zdream.pmfield.test.utils.ResourceConstant;

import static org.junit.Assert.*;

/**
 * @author Zdream
 * @date 2023-11-27
 * @since 0.0.1
 */
public class ActionPointCase {
	FoeTemplateStorage storage;

	@Before
	public void before() {
		storage = new FoeTemplateStorage();
		storage.load();
		storage.loadMovesInResource(ResourceConstant.RES_PATH_TEST_MOVES_JSON);
	}

	@Test
	public void testUseMoveWithoutActionPoint() {
		MoveTemplate movePointMove = storage.findMoveById(10000014, 1);
		assertEquals(movePointMove.name, "只使用移动点");
		MoveTemplate normalMove = storage.findMoveById(10000010, 1);
		assertEquals(normalMove.name, "肯定成功");

		assertEquals(movePointMove.actionPoint, 0);
		assertEquals(movePointMove.movePoint, 1);
		assertEquals(normalMove.actionPoint, 1);
		assertEquals(normalMove.movePoint, 0);

		Foe foe1 = Foe.builder(storage.findFoeById(4))
				.withLevel(20)
				.withMove(movePointMove)
				.withMove(normalMove)
				.build();
		Foe foe2 = Foe.builder(storage.findFoeById(1))
				.withLevel(20)
				.withMove(normalMove)
				.build();
		final StageWrapper wrapper = StageBuilderForTest.builder()
				.putFoeToOneSide(foe1)
				.putFoeToAnotherSide(foe2)
				.withStorage(storage)
				.buildWrapper();

		AtomicInteger foe1RequestCount = new AtomicInteger(0);

		// 记录 Foe 的移动点数
		AtomicInteger movePoint = new AtomicInteger(0);
		float[] time = new float[] {0};
		AtomicBoolean checked = new AtomicBoolean(false);

		wrapper.printBeforeHandleMessage();
		wrapper.onActionRequestForAll(wrapper.createDefaultController().withActionChecker(action -> {
			if (action.foe.foe != foe1) {
				return;
			}
			// 预期是第一次用 movePointMove, 第二次及以后用 movePointMove 或 normalMove
			final int actionCount = foe1RequestCount.incrementAndGet();
			if (actionCount == 1) {
				assertEquals(action.move.move, movePointMove);
				assertEquals(action.foe.actionPoint, 1);
				assertTrue(action.foe.movePoint >= 1);
				movePoint.set(action.foe.movePoint);
				time[0] = wrapper.now();
			} else if (actionCount > 1) {
				assertEquals(action.foe.actionPoint, 1);
				assertTrue(action.foe.movePoint < movePoint.get());
				assertEquals(time[0], wrapper.now(), 0);

				if (action.move.move == normalMove) {
					checked.set(true);
				} else {
					movePoint.set(action.foe.movePoint);
				}
			}
		}));

		wrapper.runUntil(stage0 -> checked.get());
		assertTrue(checked.get());
	}

	@Test
	public void testUseAllActionPointMove() {
		MoveTemplate skippedMove = storage.findMoveById(10000016, 1);
		assertEquals(skippedMove.name, "使用所有行动点");
		assertEquals(skippedMove.actionPoint, MoveTemplate.COST_ALL);

		Foe foe1 = Foe.builder(storage.findFoeById(4))
				.withLevel(20)
				.withMove(skippedMove)
				.build();
		Foe foe2 = Foe.builder(storage.findFoeById(1))
				.withLevel(20)
				.withMove(skippedMove)
				.build();
		final StageWrapper wrapper = StageBuilderForTest.builder()
				.putFoeToOneSide(foe1)
				.putFoeToAnotherSide(foe2)
				.withStorage(storage)
				.buildWrapper();

		System.out.println("测试: 跳过回合后下一轮是另一个 turn");
		AtomicBoolean actionRequested = new AtomicBoolean(false);
		AtomicBoolean turnFinished = new AtomicBoolean(false);
		AtomicBoolean checked = new AtomicBoolean(false);

		wrapper.printBeforeHandleMessage();
		wrapper.onDefaultActionRequest();
		wrapper.onMessage(ActionRequestMessage.class, message -> {
			if (actionRequested.get()) {
				assertTrue(turnFinished.get());
				checked.set(true);
			}
			actionRequested.set(true);
		});
		wrapper.onMessage(TurnFinishedMessage.class, message -> turnFinished.set(true));

		wrapper.runUntil(stage -> checked.get());
	}
}
